package com.shm.leetcode;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

/**
 * 299. 猜数字游戏
 * 你在和朋友一起玩 猜数字（Bulls and Cows）游戏，该游戏规则如下：
 *
 * 写出一个秘密数字，并请朋友猜这个数字是多少。朋友每猜测一次，你就会给他一个包含下述信息的提示：
 *
 * 猜测数字中有多少位属于数字和确切位置都猜对了（称为 "Bulls", 公牛），
 * 有多少位属于数字猜对了但是位置不对（称为 "Cows", 奶牛）。也就是说，这次猜测中有多少位非公牛数字可以通过重新排列转换成公牛数字。
 * 给你一个秘密数字 secret 和朋友猜测的数字 guess ，请你返回对朋友这次猜测的提示。
 *
 * 提示的格式为 "xAyB" ，x 是公牛个数， y 是奶牛个数，A 表示公牛，B 表示奶牛。
 *
 * 请注意秘密数字和朋友猜测的数字都可能含有重复数字。
 *
 *
 *
 * 示例 1:
 *
 * 输入: secret = "1807", guess = "7810"
 * 输出: "1A3B"
 * 解释: 数字和位置都对（公牛）用 '|' 连接，数字猜对位置不对（奶牛）的采用斜体加粗标识。
 * "1807"
 *   |
 * "7810"
 * 示例 2:
 *
 * 输入: secret = "1123", guess = "0111"
 * 输出: "1A1B"
 * 解释: 数字和位置都对（公牛）用 '|' 连接，数字猜对位置不对（奶牛）的采用斜体加粗标识。
 * "1123"        "1123"
 *   |      or     |
 * "0111"        "0111"
 * 注意，两个不匹配的 1 中，只有一个会算作奶牛（数字猜对位置不对）。通过重新排列非公牛数字，其中仅有一个 1 可以成为公牛数字。
 * 示例 3：
 *
 * 输入：secret = "1", guess = "0"
 * 输出："0A0B"
 * 示例 4：
 *
 * 输入：secret = "1", guess = "1"
 * 输出："1A0B"
 *
 *
 * 提示：
 *
 * 1 <= secret.length, guess.length <= 1000
 * secret.length == guess.length
 * secret 和 guess 仅由数字组成
 * @author SHM
 */
public class GetHint {

    public String getHint_1(String secret, String guess) {
        int x=0,y=0;
        int n = guess.length();
        HashMap<Character,Integer> map = new HashMap<>();
        for (int i = 0; i < n; i++) {
            map.put(guess.charAt(i),map.getOrDefault(guess.charAt(i),0)+1);
        }
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < n; i++) {
            if (secret.charAt(i)==guess.charAt(i)){
                x++;
                map.put(secret.charAt(i),map.get(secret.charAt(i))-1);
                set.add(i);
            }
        }
        for (int i = 0; i < n; i++) {
            if (!set.contains(i)&&map.getOrDefault(secret.charAt(i),0)>0){
                y++;
                map.put(secret.charAt(i),map.get(secret.charAt(i))-1);
            }
        }
        return x+"A"+y+"B";
    }

    /**
     * 方法一：遍历
     * 根据题意，对于公牛，需要满足数字和确切位置都猜对。我们可以遍历 \textit{secret}secret 和 \textit{guess}guess，统计满足 \textit{secret}[i]=\textit{guess}[i]secret[i]=guess[i] 的下标个数，即为公牛的个数。
     *
     * 对于奶牛，需要满足数字猜对但是位置不对。我们可以在 \textit{secret}[i]\ne\textit{guess}[i]secret[i]
     * 
     * ​
     *  =guess[i] 时，分别统计 \textit{secret}secret 和 \textit{guess}guess 的各个字符的出现次数，记在两个长度为 1010 的数组中。根据题目所述的「这次猜测中有多少位非公牛数字可以通过重新排列转换成公牛数字」，由于多余的数字无法匹配，对于 \texttt{0}0 到 \texttt{9}9 的每位数字，应取其在 \textit{secret}secret 和 \textit{guess}guess 中的出现次数的最小值。将每位数字出现次数的最小值累加，即为奶牛的个数。
     *
     * 复杂度分析
     *
     * 时间复杂度：O(N)O(N)，其中 NN 是字符串 \textit{secret}secret 的长度。
     *
     * 空间复杂度：O(C)O(C)。需要常数个空间统计字符出现次数，由于我们统计的是数字字符，因此 C=10C=10。
     *
     * 作者：LeetCode-Solution
     * 链接：https://leetcode-cn.com/problems/bulls-and-cows/solution/cai-shu-zi-you-xi-by-leetcode-solution-q9lz/
     * @param secret
     * @param guess
     * @return
     */
    public String getHint(String secret, String guess) {
        int x = 0, y = 0;
        int n = guess.length();
        int[] cntS=new int[10],cntG=new int[10];
        for (int i = 0; i < n; i++) {
            int s = secret.charAt(i) - '0', g = guess.charAt(i) - '0';
            if (s == g) {
                x++;
            } else {
                cntS[s]++;
                cntG[g]++;
            }
        }
        for (int i = 0; i < 10; i++) {
            y+=Math.min(cntG[i],cntS[i]);
        }
        return x+"A"+y+"B";
    }
}
